package com.zzw.basic.classloader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;

public class CompileLoader extends ClassLoader{

	private byte[] getBytes(String filename){
		File file = new File(filename);
		long len = file.length();
		byte[] raw = new byte[(int)len];
		int r;
		try {
			FileInputStream fileInputStream = new FileInputStream(file);
			r = fileInputStream.read(raw);
			if(r != len){
				throw new IOException("" + r + "!=" + len);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return raw;
	}
	
	private boolean complie(String javaFile) throws IOException{
		System.out.println("CompileClassLoader:" + javaFile + "...");
		Process p = Runtime.getRuntime().exec("javac" + javaFile);
		try {
			p.waitFor();
		} catch (Exception e) {
			e.printStackTrace();
		}
		int ret = p.exitValue();
		return ret == 0;
	}
	
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		Class clazz = null;
		String fileStub = name.replace(".", "/");
		String javaFilename = fileStub + ".java";
		String classFilename = fileStub + ".class";
		File javaFile = new File(javaFilename);
		File classFile = new File(classFilename);
		if(javaFile.exists() && (!classFile.exists()
				|| javaFile.lastModified() > classFile.lastModified())){
			try {
				if(!complie(javaFilename) || !classFile.exists()){
					throw new ClassNotFoundException("ClassNotFoundException:" + javaFilename);
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if(classFile.exists()){
			byte[] raw = getBytes(classFilename);
			clazz = defineClass(name, raw, 0, raw.length);
		}
		if(clazz == null){
			throw new ClassNotFoundException(name);
		}
		return clazz;
	}
	
	public static void main(String[] args) throws Exception {
		if(args.length < 1){
			System.out.println("java CompileClassLoader ClassName");
		}
		String progClass = args[0];
		String[] progArgs = new String[args.length - 1];
		System.arraycopy(args, 1, progArgs, 0, progArgs.length);
		CompileLoader cc1 = new CompileLoader();
		Class<?> clazz = cc1.loadClass(progClass);
		Method main = clazz.getMethod("main",(new String[0].getClass()));
		Object argsArray[] = {progArgs};
		main.invoke(null, argsArray);
	}
}